Started: 2020-09-10
Last edited: 2020-11-23 12:38:30

library(tidyverse)

# single cell
library(Seurat)

# plotting
library(patchwork)
library(ggthemes)

1 Background

Alice had performed bulk-RNA seq on the placenta sample from COVID-19 positive mothers and control placentas and has a list of genes that were differentially expressed. Here we will use the single-cell RNA seq data to figure out in which cell types those DE genes are expressed.

2 Data

I have already annotated the clusters. The annotated data (a seurat object) was saved as .rds, which we have to read.

seur <- readRDS("../results/02_annotation/seurat-object_annotated.rds")
# set active assay
DefaultAssay(seur) <- "SCT"

# set levels for idents (use merged_annotations)
seur@meta.data$annotation_merged <- factor(seur@meta.data$annotation_merged,
                                           levels = sort(unique(seur@meta.data$annotation_merged)))

# set idents
Idents(seur) <- seur@meta.data$annotation_merged

3 DE genes

Below are the DE genes sent by Alice.

genes <- list()

genes$focused <- c("HSPA1A", "PPP1R11", "LY6GLY6C", "ITGAX", "IFITM1", "C1QC", "CCL2", "OAS3", "MX1")
genes$analysis1 <- c("HSPA1A", "FMC1-LUC7L2", "HSPA1B", "AC011511.4", "PPP1R11", "AL139300.1", "LY6GLY6C")
genes$analysis2 <- c("ITGAX", "OAS3", "IFITM1", "MX1", "C1QC", "MX2", "CCL2")
genes$additional <- c("C1QTNF2", "LYVE1", "TREM1", "FOLR2", "C1QB", "CCL2", "TNFRSF10C", "CXCL9", "IL1R2", "IL36A", "CD28", "OAS1", "IL1RN", "CD36", "CXCR2",   "SERPING1", "CXCR1", "TNFRSF10C", "C1QA", "HCST", "IL36A", "IL4R", "LY96", "IL1R2", "CXCR2", "CXCL2", "S100A7", "IFITM3", "SELENOM", "SELENOP", "C3AR1", "CCL2", "CCL8")
genes$entry <- c("ACE2", "TMPRSS2", "BSG", "DPP4", "CTSL", "CTSB", "FURIN")
genes$new <- c("FCGRT", "GPX1", "GPX3", "GPX4", "DIO3", "TXNRD1", "TXNRD2", "TXNRD3")

all.genes <- c(genes$focused, genes$analysis1, genes$analysis2, genes$additional, genes$entry, genes$new) %>% 
  unique() %>% 
  sort()

4 Plots

4.1 Dotplot for all genes

# dotplot function
DotPlot2 <- function(object = seur, assay = "SCT", features, title = "", ...) {
  p <- DotPlot(object, 
               assay = assay,
               features = features, 
               dot.scale = 4, 
               dot.min = 0.01,
               ...) +
    coord_flip() +
    labs(caption = paste0("sctransform normalized expression"), title = title) +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
          panel.grid.minor = element_blank(),
          panel.grid.major = element_line(size = 0.1),
          legend.key.size = unit(0.75, "line"))
  
  return(p)
}
DotPlot2(features = all.genes)
The following requested variables were not found: AC011511.4, AL139300.1, FMC1-LUC7L2, GPX1, LY6GLY6C

cowplot::ggsave2(last_plot(), 
                 filename = "../results/03_candidate-genes/plots/dotplot_all-genes.pdf", 
                 width = 6.5, height = 8.5, units = "in")

4.2 Individual genes

# violin function
VlnPlot2 <- function(object = seur, assay = "SCT", feature, ...) {
  p <- VlnPlot(object = object, 
               features = feature, 
               assay = assay, 
               same.y.lims = FALSE,
               split.by = "covid", 
               split.plot = TRUE,
               pt.size = 0,
               ...) + 
    coord_cartesian(clip = "off") +
    theme_classic() +
    theme(
      plot.title = element_text(size = 7, colour = "black"),
      panel.grid.minor = element_blank(),
      panel.grid.major = element_line(size = 0.2),
      axis.line = element_line(size = 0.25),
      axis.ticks = element_line(size = 0.25),
      axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5, 
                                 size = 6, color = "black"),
      axis.title.x = element_blank(),
      axis.title.y = element_text(size = 6, color = "black"),
      axis.text.y = element_text(size = 6, color = "black"),
      legend.key.size = unit(0.50, "lines"),
      legend.position = c(1, 1),
      legend.direction = "horizontal",
      legend.justification = c(1, 0),
      legend.text = element_text(size = 6, colour = "black")
    )
  
  p$layers[[1]]$aes_params$size = 0.25 # violin stroke
  
  return(p)
}
# umap function
FeaturePlot2 <- function(object = seur, feature, ...) {
  DefaultAssay(object) <- "SCT"
  FeaturePlot(object, 
              feature = feature, 
              split.by = "covid",
              pt.size = 0.1, 
              order = TRUE, 
              min.cutoff = "q10", 
              combine = TRUE,
              ...) &
    plot_annotation(title = feature) &
    theme_bw() +
    theme(panel.grid.major = element_line(size = 0.25),
          panel.grid.minor = element_blank(),
          legend.key.size = unit(0.50, "line"),
          legend.text = element_text(size = 6, angle = 90, hjust = 1),
          legend.position = "bottom",
          axis.title = element_text(size = 6),
          plot.title = element_text(size = 7),
          axis.title.y.right = element_blank(),
          axis.text = element_blank(),
          aspect.ratio = 1)
}

for(i in all.genes[all.genes %in% rownames(seur)]) {
  vplot <- VlnPlot2(feature = i)
  fplot <- FeaturePlot2(feature = i, max.cutoff = "q99")
  
  cowplot::ggsave2(vplot, 
                   filename = paste0("../results/03_candidate-genes/plots/", i, "_violinplot.pdf"),
                   width = 3.5, height = 2, units = "in")
  
  cowplot::ggsave2(fplot, 
                   filename = paste0("../results/03_candidate-genes/plots/", i, "_on-umap.png"),
                   width = 3.5, height = 2.5, units = "in")
  
  vf <- vplot + fplot + 
  plot_layout(ncol = 1, widths = c(1, 0.5))
  print(vf)
}

For some genes, the umap plots and violin plots seem to disagree with each other. That is, the gene is expressed at higher level in “covid” than “control” according to the violin plot, but the colours appear stronger for “control” on umap plots. I think this is simply because of the differing number of cells from “control” and “covid”. We have fewer cells from “covid” samples (as is evident also on the umap plots), so the lightness or sparseness of blue on umap plots just reflect that. Violin plots on the other hand scale the width of violins to the total number of cells in each group, so this difference is not seen in violin plots.

5 Split dotplots

## data -----------------------------------------------------------------------
celltypes <- unique(seur$annotation_merged) %>% sort()
de.genes <- list()
for(i in celltypes){
  de.genes[[i]] <- read.csv(
    paste0("../results/04_de-genes-by-celltype/logfc_0.40/de/files/de-genes_", i, ".csv")
  )
  de.genes[[i]] <- dplyr::rename(de.genes[[i]], "gene" = "X")
  de.genes[[i]]$celltype <- i
}
## create celltype_covid ident to use for seurat dotplot ----------------------
seur$celltype_covid <- paste0(seur$annotation_merged, "_", seur$covid)
## theme for DE genes faceted dotplot -----------------------------------------
theme_dotplot <- theme(
  plot.margin = margin(5.5, 5.5, 1, 5.5),
  panel.background = element_blank(),
  text = element_text(color = "Black"),
  panel.grid = element_blank(),
  panel.border = element_rect(fill = NA, size = 0.25, color = "grey"),
  axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5, size = 5, color = "Black"),
  axis.text.y = element_text(size = 5, color = "Black"),
  axis.title = element_blank(),
  axis.ticks = element_line(size = 0.25, color = "grey"),
  strip.text.x = element_text(angle = 90, hjust = 0, vjust = 0.5, 
                              size = 5.25, color = "Black"),
  strip.background = element_blank(),
  legend.title = element_text(size = 5.25),
  legend.position = "bottom",
  legend.direction = "horizontal",
  legend.box = "horizontal",
  legend.background = element_blank(),
  legend.box.spacing = unit(0.5, "lines"),
  legend.title.align = 0,
  legend.text = element_text(size = 5),
  legend.key.size = unit(0.5, "lines"),
  legend.key = element_blank(),
  panel.spacing.x = unit(0, "lines")
)
## dotplot function -----------------------------------------------------------
plot_splitdot <- function(object, features, exclude.celltypes = c()) {
  
  # idents combined for celltype and covid
  Idents(object) <- object$celltype_covid
  
  # run seurat's dotplot
  p <- Seurat::DotPlot(
    object = object, 
    assay = "SCT", 
    features = features
    )
  
  # extract plotting data
  p.dat <- p$data
  p.dat$celltype <- gsub(p.dat$id, pattern = "(.+)_([a-z]{5})", replacement = "\\1")
  p.dat$covid <- gsub(p.dat$id, pattern = "(.+)_([a-z]{5})", replacement = "\\2")
  
  # subset for celltypes of interest
  p.sub <- p.dat[!(p.dat$celltype %in% exclude.celltypes), ]
  
  # redo scaling for selected celltype_covid idents
  p.wide <- pivot_wider(p.sub,
                        id_cols = features.plot, 
                        names_from = id, 
                        values_from = avg.exp) %>% 
    as.data.frame()
  
  rownames(p.wide) <- p.wide$features.plot
  p.wide$features.plot <- NULL
  p.scaled <- t(p.wide) %>% 
    scale(center = TRUE, scale = TRUE) %>% 
    t() %>% 
    as.data.frame()
  p.scaled$features.plot <- rownames(p.scaled)
  
  # melt rescaled avg.exp
  p.scaled.long <- pivot_longer(
    data = p.scaled, 
    cols = names(p.scaled)[names(p.scaled) != "features.plot"], 
    names_to = "id", 
    values_to = "scaled.new")
  
  # cap min and max scaled value; same as col.min and col.max in Seurat::DotPlot
  p.scaled.long$scaled.new[p.scaled.long$scaled.new >  2.5] <-  2.5
  p.scaled.long$scaled.new[p.scaled.long$scaled.new < -2.5] <- -2.5
  
  # join with p.dat to get pct.exp and scaled.new in the same df
  plot.dat <- dplyr::inner_join(x = p.dat, 
                                y = p.scaled.long, 
                                by = c("features.plot", "id"))
  
  # clustering for ordering
  cdat <- pivot_wider(data =  plot.dat, id_cols = "features.plot", 
                      names_from = id,
                      values_from = scaled.new) %>% 
    as.data.frame()

  rownames(cdat) <- cdat$features.plot
  cdat$features.plot <- NULL
  cor.matrix <- cor(t(cdat))
  
  # reorder correlation matrix based on clustering
  dd <- as.dist((1 - cor.matrix))
  hc <- hclust(dd, method = 'complete')
  cdat  <- cdat[hc$order, ]

  # reorder factor levels based on clustering
  plot.dat$features.plot <- factor(plot.dat$features.plot, 
                                   levels = rownames(cdat))
  
  # prepare annotation data (hpline for DE genes)
  de.ann <- de.genes
  de.ann <- do.call(rbind, de.ann)
  de.ann <- subset(de.ann, 
                   gene %in% plot.dat$features.plot &
                     celltype %in% plot.dat$celltype
  )
  de.ann$diff.exp <- de.ann$p_val_adj < 0.05
  de.ann$diff.exp <- tolower(as.character(de.ann$diff.exp))
  
  # plot
  q <- ggplot(data = plot.dat, 
              aes(x = covid, y = features.plot)) +
    geom_point(aes(fill = scaled.new, size = pct.exp), 
               shape = 21, stroke = 0, 
               color = "White") +
    scale_fill_gradient(low = "White", 
                        high = "#d94801", 
                        name = "avg. exp. (scaled)",
                        guide = guide_colorbar(
                          title.position = "top", 
                          title.hjust = 0.5, 
                          ticks.colour = "black"
                        )
    ) +
    scale_x_discrete(breaks = c("cntrl", "covid"), 
                     labels = c("ctrl", "COVID")) +
    scale_size_area(max_size = 2.5,
                    name = "% cells with exp.",
                    guide = guide_legend(
                      override.aes = list(
                        color = "White", 
                        fill = "Grey30"
                      ),
                      title.position = "top", title.hjust = 0.5
                    )
    ) +
    facet_grid(. ~ celltype) +
    ungeviz::geom_hpline(data = de.ann,
                         aes(y = gene, x = 1.5, color = diff.exp),
                         size = 0.30, width = 1, lineend = "butt") +
    scale_color_manual(breaks = "true",
                       labels = "< 0.05",
                       values = "Black",
                       name = "DE adj.p",
                       guide = guide_legend(title.position = "top",
                                            title.hjust = 0.5)) +
    theme_dotplot
  
  return(q)
  
}
# plot new gene list
splitdot1 <- plot_splitdot(
  object = seur, 
  features = genes$new
)
The following requested variables were not found: GPX1
cowplot::ggsave2(
  splitdot1,
  filename = "../results/03_candidate-genes/plots/splitdot_set1.pdf",
  width = 3.75, height = 2, units = "in"
)

splitdot1

6 Mean expression for all genes

avg <- AverageExpression(seur, assays = "SCT") %>% .$SCT
Finished averaging SCT for cluster dec.APC
Finished averaging SCT for cluster dec.Bcells
Finished averaging SCT for cluster dec.DSC
Finished averaging SCT for cluster dec.Endo
Finished averaging SCT for cluster dec.FB
Finished averaging SCT for cluster dec.Gran
Finished averaging SCT for cluster dec.Mono_1
Finished averaging SCT for cluster dec.Mono_2
Finished averaging SCT for cluster dec.NK_1
Finished averaging SCT for cluster dec.NK_2
Finished averaging SCT for cluster dec.NK_3
Finished averaging SCT for cluster dec.SMC
Finished averaging SCT for cluster dec.Tcell_1
Finished averaging SCT for cluster dec.Tcell_2
Finished averaging SCT for cluster dec.Tcell_3
Finished averaging SCT for cluster vil.Ery
Finished averaging SCT for cluster vil.EVT
Finished averaging SCT for cluster vil.FB
Finished averaging SCT for cluster vil.Hofb
Finished averaging SCT for cluster vil.SCT
Finished averaging SCT for cluster vil.VCT
avg$gene_name <- rownames(avg)
avg <- relocate(avg, gene_name)

write.csv(avg, "../results/03_candidate-genes/mean-expression_assay-sct_slot-data.csv", row.names = FALSE)

7 Session Info

```r
sessionInfo()

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiUiB2ZXJzaW9uIDQuMC4yICgyMDIwLTA2LTIyKVxuUGxhdGZvcm06IHg4Nl82NC1hcHBsZS1kYXJ3aW4xNy4wICg2NC1iaXQpXG5SdW5uaW5nIHVuZGVyOiBtYWNPUyBNb2phdmUgMTAuMTQuNlxuXG5NYXRyaXggcHJvZHVjdHM6IGRlZmF1bHRcbkJMQVM6ICAgL1N5c3RlbS9MaWJyYXJ5L0ZyYW1ld29ya3MvQWNjZWxlcmF0ZS5mcmFtZXdvcmsvVmVyc2lvbnMvQS9GcmFtZXdvcmtzL3ZlY0xpYi5mcmFtZXdvcmsvVmVyc2lvbnMvQS9saWJCTEFTLmR5bGliXG5MQVBBQ0s6IC9MaWJyYXJ5L0ZyYW1ld29ya3MvUi5mcmFtZXdvcmsvVmVyc2lvbnMvNC4wL1Jlc291cmNlcy9saWIvbGliUmxhcGFjay5keWxpYlxuXG5sb2NhbGU6XG5bMV0gZW5fVVMuVVRGLTgvZW5fVVMuVVRGLTgvZW5fVVMuVVRGLTgvQy9lbl9VUy5VVEYtOC9lbl9VUy5VVEYtOFxuXG5hdHRhY2hlZCBiYXNlIHBhY2thZ2VzOlxuWzFdIHN0YXRzICAgICBncmFwaGljcyAgZ3JEZXZpY2VzIHV0aWxzICAgICBkYXRhc2V0cyAgbWV0aG9kcyAgIGJhc2UgICAgIFxuXG5vdGhlciBhdHRhY2hlZCBwYWNrYWdlczpcbiBbMV0gZ2d0aGVtZXNfNC4yLjAgIHBhdGNod29ya18xLjAuMSBTZXVyYXRfMy4yLjIgICAgZm9yY2F0c18wLjUuMCAgIHN0cmluZ3JfMS40LjAgICBkcGx5cl8xLjAuMiAgICAgcHVycnJfMC4zLjQgICAgXG4gWzhdIHJlYWRyXzEuMy4xICAgICB0aWR5cl8xLjEuMiAgICAgdGliYmxlXzMuMC40ICAgIGdncGxvdDJfMy4zLjIgICB0aWR5dmVyc2VfMS4zLjBcblxubG9hZGVkIHZpYSBhIG5hbWVzcGFjZSAoYW5kIG5vdCBhdHRhY2hlZCk6XG4gIFsxXSBSdHNuZV8wLjE1ICAgICAgICAgICAgIGNvbG9yc3BhY2VfMi4wLTAgICAgICAgZGVsZGlyXzAuMS0yOCAgICAgICAgICBlbGxpcHNpc18wLjMuMSAgICAgICAgXG4gIFs1XSBnZ3JpZGdlc18wLjUuMiAgICAgICAgIGZzXzEuNS4wICAgICAgICAgICAgICAgc3BhdHN0YXQuZGF0YV8xLjQtMyAgICByc3R1ZGlvYXBpXzAuMTIgICAgICAgXG4gIFs5XSBmYXJ2ZXJfMi4wLjMgICAgICAgICAgIGxlaWRlbl8wLjMuMyAgICAgICAgICAgbGlzdGVudl8wLjguMCAgICAgICAgICBnZ3JlcGVsXzAuOC4yICAgICAgICAgXG4gWzEzXSBmYW5zaV8wLjQuMSAgICAgICAgICAgIGx1YnJpZGF0ZV8xLjcuOSAgICAgICAgeG1sMl8xLjMuMiAgICAgICAgICAgICBjb2RldG9vbHNfMC4yLTE2ICAgICAgXG4gWzE3XSBzcGxpbmVzXzQuMC4yICAgICAgICAgIGtuaXRyXzEuMzAgICAgICAgICAgICAgcG9seWNsaXBfMS4xMC0wICAgICAgICBqc29ubGl0ZV8xLjcuMSAgICAgICAgXG4gWzIxXSBicm9vbV8wLjcuMCAgICAgICAgICAgIGljYV8xLjAtMiAgICAgICAgICAgICAgY2x1c3Rlcl8yLjEuMCAgICAgICAgICBkYnBseXJfMS40LjQgICAgICAgICAgXG4gWzI1XSBwbmdfMC4xLTcgICAgICAgICAgICAgIHV3b3RfMC4xLjggICAgICAgICAgICAgc2N0cmFuc2Zvcm1fMC4zLjEuOTAwMiBzaGlueV8xLjUuMCAgICAgICAgICAgXG4gWzI5XSBjb21waWxlcl80LjAuMiAgICAgICAgIGh0dHJfMS40LjIgICAgICAgICAgICAgYmFja3BvcnRzXzEuMi4wICAgICAgICBhc3NlcnR0aGF0XzAuMi4xICAgICAgXG4gWzMzXSBNYXRyaXhfMS4yLTE4ICAgICAgICAgIGZhc3RtYXBfMS4wLjEgICAgICAgICAgbGF6eWV2YWxfMC4yLjIgICAgICAgICBjbGlfMi4xLjAgICAgICAgICAgICAgXG4gWzM3XSBsYXRlcl8xLjEuMC4xICAgICAgICAgIGh0bWx0b29sc18wLjUuMCAgICAgICAgdG9vbHNfNC4wLjIgICAgICAgICAgICByc3ZkXzEuMC4zICAgICAgICAgICAgXG4gWzQxXSBpZ3JhcGhfMS4yLjUgICAgICAgICAgIGd0YWJsZV8wLjMuMCAgICAgICAgICAgZ2x1ZV8xLjQuMiAgICAgICAgICAgICByZXNoYXBlMl8xLjQuNCAgICAgICAgXG4gWzQ1XSBSQU5OXzIuNi4xICAgICAgICAgICAgIHNwYXRzdGF0XzEuNjQtMSAgICAgICAgUmNwcF8xLjAuNSAgICAgICAgICAgICBjZWxscmFuZ2VyXzEuMS4wICAgICAgXG4gWzQ5XSB2Y3Ryc18wLjMuNCAgICAgICAgICAgIG5sbWVfMy4xLTE0OSAgICAgICAgICAgbG10ZXN0XzAuOS0zOCAgICAgICAgICB4ZnVuXzAuMTkgICAgICAgICAgICAgXG4gWzUzXSBnbG9iYWxzXzAuMTMuMSAgICAgICAgIHJ2ZXN0XzAuMy42ICAgICAgICAgICAgbWltZV8wLjkgICAgICAgICAgICAgICBtaW5pVUlfMC4xLjEuMSAgICAgICAgXG4gWzU3XSBsaWZlY3ljbGVfMC4yLjAgICAgICAgIGlybGJhXzIuMy4zICAgICAgICAgICAgZ29mdGVzdF8xLjItMiAgICAgICAgICBmdXR1cmVfMS4yMC4xICAgICAgICAgXG4gWzYxXSBNQVNTXzcuMy01MiAgICAgICAgICAgIHpvb18xLjgtOCAgICAgICAgICAgICAgc2NhbGVzXzEuMS4xICAgICAgICAgICBzcGF0c3RhdC51dGlsc18xLjE3LTAgXG4gWzY1XSBobXNfMC41LjMgICAgICAgICAgICAgIHByb21pc2VzXzEuMS4xICAgICAgICAgcGFyYWxsZWxfNC4wLjIgICAgICAgICBSQ29sb3JCcmV3ZXJfMS4xLTIgICAgXG4gWzY5XSB5YW1sXzIuMi4xICAgICAgICAgICAgIGdyaWRFeHRyYV8yLjMgICAgICAgICAgcmV0aWN1bGF0ZV8xLjE2ICAgICAgICBwYmFwcGx5XzEuNC0zICAgICAgICAgXG4gWzczXSBycGFydF80LjEtMTUgICAgICAgICAgIHN0cmluZ2lfMS41LjMgICAgICAgICAgcmxhbmdfMC40LjggICAgICAgICAgICBwa2djb25maWdfMi4wLjMgICAgICAgXG4gWzc3XSBtYXRyaXhTdGF0c18wLjU3LjAgICAgIGV2YWx1YXRlXzAuMTQgICAgICAgICAgbGF0dGljZV8wLjIwLTQxICAgICAgICB0ZW5zb3JfMS41ICAgICAgICAgICAgXG4gWzgxXSBST0NSXzEuMC0xMSAgICAgICAgICAgIGxhYmVsaW5nXzAuNC4yICAgICAgICAgaHRtbHdpZGdldHNfMS41LjEgICAgICBjb3dwbG90XzEuMS4wICAgICAgICAgXG4gWzg1XSB0aWR5c2VsZWN0XzEuMS4wICAgICAgIHBhcmFsbGVsbHlfMS4yMS4wICAgICAgUmNwcEFubm95XzAuMC4xNiAgICAgICBwbHlyXzEuOC42ICAgICAgICAgICAgXG4gWzg5XSBtYWdyaXR0cl8xLjUgICAgICAgICAgIFI2XzIuNS4wICAgICAgICAgICAgICAgZ2VuZXJpY3NfMC4wLjIgICAgICAgICBEQklfMS4xLjAgICAgICAgICAgICAgXG4gWzkzXSBtZ2N2XzEuOC0zMSAgICAgICAgICAgIHBpbGxhcl8xLjQuNiAgICAgICAgICAgaGF2ZW5fMi4zLjEgICAgICAgICAgICB3aXRocl8yLjMuMCAgICAgICAgICAgXG4gWzk3XSBmaXRkaXN0cnBsdXNfMS4xLTEgICAgIGFiaW5kXzEuNC01ICAgICAgICAgICAgc3Vydml2YWxfMy4yLTMgICAgICAgICBmdXR1cmUuYXBwbHlfMS42LjAgICAgXG5bMTAxXSBtb2RlbHJfMC4xLjggICAgICAgICAgIGNyYXlvbl8xLjMuNCAgICAgICAgICAgS2VyblNtb290aF8yLjIzLTE3ICAgICBwbG90bHlfNC45LjIuMSAgICAgICAgXG5bMTA1XSBybWFya2Rvd25fMi4zICAgICAgICAgIGdyaWRfNC4wLjIgICAgICAgICAgICAgcmVhZHhsXzEuMy4xICAgICAgICAgICBkYXRhLnRhYmxlXzEuMTMuMCAgICAgXG5bMTA5XSBibG9iXzEuMi4xICAgICAgICAgICAgIHJlcHJleF8wLjMuMCAgICAgICAgICAgZGlnZXN0XzAuNi4yNyAgICAgICAgICB4dGFibGVfMS44LTQgICAgICAgICAgXG5bMTEzXSBodHRwdXZfMS41LjQgICAgICAgICAgIG11bnNlbGxfMC41LjAgICAgICAgICAgdmlyaWRpc0xpdGVfMC4zLjAgICAgIFxuIn0= -->

R version 4.0.2 (2020-06-22) Platform: x86_64-apple-darwin17.0 (64-bit) Running under: macOS Mojave 10.14.6

Matrix products: default BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale: [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages: [1] stats graphics grDevices utils datasets methods base

other attached packages: [1] ggthemes_4.2.0 patchwork_1.0.1 Seurat_3.2.2 forcats_0.5.0 stringr_1.4.0 dplyr_1.0.2 purrr_0.3.4
[8] readr_1.3.1 tidyr_1.1.2 tibble_3.0.4 ggplot2_3.3.2 tidyverse_1.3.0

loaded via a namespace (and not attached): [1] Rtsne_0.15 colorspace_2.0-0 deldir_0.1-28 ellipsis_0.3.1
[5] ggridges_0.5.2 fs_1.5.0 spatstat.data_1.4-3 rstudioapi_0.12
[9] farver_2.0.3 leiden_0.3.3 listenv_0.8.0 ggrepel_0.8.2
[13] fansi_0.4.1 lubridate_1.7.9 xml2_1.3.2 codetools_0.2-16
[17] splines_4.0.2 knitr_1.30 polyclip_1.10-0 jsonlite_1.7.1
[21] broom_0.7.0 ica_1.0-2 cluster_2.1.0 dbplyr_1.4.4
[25] png_0.1-7 uwot_0.1.8 sctransform_0.3.1.9002 shiny_1.5.0
[29] compiler_4.0.2 httr_1.4.2 backports_1.2.0 assertthat_0.2.1
[33] Matrix_1.2-18 fastmap_1.0.1 lazyeval_0.2.2 cli_2.1.0
[37] later_1.1.0.1 htmltools_0.5.0 tools_4.0.2 rsvd_1.0.3
[41] igraph_1.2.5 gtable_0.3.0 glue_1.4.2 reshape2_1.4.4
[45] RANN_2.6.1 spatstat_1.64-1 Rcpp_1.0.5 cellranger_1.1.0
[49] vctrs_0.3.4 nlme_3.1-149 lmtest_0.9-38 xfun_0.19
[53] globals_0.13.1 rvest_0.3.6 mime_0.9 miniUI_0.1.1.1
[57] lifecycle_0.2.0 irlba_2.3.3 goftest_1.2-2 future_1.20.1
[61] MASS_7.3-52 zoo_1.8-8 scales_1.1.1 spatstat.utils_1.17-0 [65] hms_0.5.3 promises_1.1.1 parallel_4.0.2 RColorBrewer_1.1-2
[69] yaml_2.2.1 gridExtra_2.3 reticulate_1.16 pbapply_1.4-3
[73] rpart_4.1-15 stringi_1.5.3 rlang_0.4.8 pkgconfig_2.0.3
[77] matrixStats_0.57.0 evaluate_0.14 lattice_0.20-41 tensor_1.5
[81] ROCR_1.0-11 labeling_0.4.2 htmlwidgets_1.5.1 cowplot_1.1.0
[85] tidyselect_1.1.0 parallelly_1.21.0 RcppAnnoy_0.0.16 plyr_1.8.6
[89] magrittr_1.5 R6_2.5.0 generics_0.0.2 DBI_1.1.0
[93] mgcv_1.8-31 pillar_1.4.6 haven_2.3.1 withr_2.3.0
[97] fitdistrplus_1.1-1 abind_1.4-5 survival_3.2-3 future.apply_1.6.0
[101] modelr_0.1.8 crayon_1.3.4 KernSmooth_2.23-17 plotly_4.9.2.1
[105] rmarkdown_2.3 grid_4.0.2 readxl_1.3.1 data.table_1.13.0
[109] blob_1.2.1 reprex_0.3.0 digest_0.6.27 xtable_1.8-4
[113] httpuv_1.5.4 munsell_0.5.0 viridisLite_0.3.0
```

LS0tCnRpdGxlOiAiRXhwcmVzc2lvbiBvZiBERSBnZW5lcyIKYXV0aG9yOiAiQXJ1biBDaGF2YW4iCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKYmlibGlvZ3JhcGh5OiAuLi9yZWZzLmJpYgotLS0KU3RhcnRlZDogMjAyMC0wOS0xMCAgCkxhc3QgZWRpdGVkOiBgciBmb3JtYXQoU3lzLnRpbWUoKSlgCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCiMgc2luZ2xlIGNlbGwKbGlicmFyeShTZXVyYXQpCgojIHBsb3R0aW5nCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGdndGhlbWVzKQpgYGAKCgojIEJhY2tncm91bmQKQWxpY2UgaGFkIHBlcmZvcm1lZCBidWxrLVJOQSBzZXEgb24gdGhlIHBsYWNlbnRhIHNhbXBsZSBmcm9tIENPVklELTE5IHBvc2l0aXZlIG1vdGhlcnMgYW5kIGNvbnRyb2wgcGxhY2VudGFzIGFuZCBoYXMgYSBsaXN0IG9mIGdlbmVzIHRoYXQgd2VyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQuIEhlcmUgd2Ugd2lsbCB1c2UgdGhlIHNpbmdsZS1jZWxsIFJOQSBzZXEgZGF0YSB0byBmaWd1cmUgb3V0IGluIHdoaWNoIGNlbGwgdHlwZXMgdGhvc2UgREUgZ2VuZXMgYXJlIGV4cHJlc3NlZC4gCgojIERhdGEKSSBoYXZlIGFscmVhZHkgYW5ub3RhdGVkIHRoZSBjbHVzdGVycy4gVGhlIGFubm90YXRlZCBkYXRhIChhIGBzZXVyYXRgIG9iamVjdCkgd2FzIHNhdmVkIGFzIGAucmRzYCwgd2hpY2ggd2UgaGF2ZSB0byByZWFkLiAKCmBgYHtyfQpzZXVyIDwtIHJlYWRSRFMoIi4uL3Jlc3VsdHMvMDJfYW5ub3RhdGlvbi9zZXVyYXQtb2JqZWN0X2Fubm90YXRlZC5yZHMiKQpgYGAKCmBgYHtyfQojIHNldCBhY3RpdmUgYXNzYXkKRGVmYXVsdEFzc2F5KHNldXIpIDwtICJTQ1QiCgojIHNldCBsZXZlbHMgZm9yIGlkZW50cyAodXNlIG1lcmdlZF9hbm5vdGF0aW9ucykKc2V1ckBtZXRhLmRhdGEkYW5ub3RhdGlvbl9tZXJnZWQgPC0gZmFjdG9yKHNldXJAbWV0YS5kYXRhJGFubm90YXRpb25fbWVyZ2VkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gc29ydCh1bmlxdWUoc2V1ckBtZXRhLmRhdGEkYW5ub3RhdGlvbl9tZXJnZWQpKSkKCiMgc2V0IGlkZW50cwpJZGVudHMoc2V1cikgPC0gc2V1ckBtZXRhLmRhdGEkYW5ub3RhdGlvbl9tZXJnZWQKYGBgCgojIERFIGdlbmVzCkJlbG93IGFyZSB0aGUgREUgZ2VuZXMgc2VudCBieSBBbGljZS4gCgpgYGB7cn0KZ2VuZXMgPC0gbGlzdCgpCgpnZW5lcyRmb2N1c2VkIDwtIGMoIkhTUEExQSIsICJQUFAxUjExIiwgIkxZNkdMWTZDIiwgIklUR0FYIiwgIklGSVRNMSIsICJDMVFDIiwgIkNDTDIiLCAiT0FTMyIsICJNWDEiKQpnZW5lcyRhbmFseXNpczEgPC0gYygiSFNQQTFBIiwgIkZNQzEtTFVDN0wyIiwgIkhTUEExQiIsCSJBQzAxMTUxMS40IiwgIlBQUDFSMTEiLCAiQUwxMzkzMDAuMSIsICJMWTZHTFk2QyIpCmdlbmVzJGFuYWx5c2lzMiA8LSBjKCJJVEdBWCIsICJPQVMzIiwgIklGSVRNMSIsICJNWDEiLCAiQzFRQyIsICJNWDIiLCAiQ0NMMiIpCmdlbmVzJGFkZGl0aW9uYWwgPC0gYygiQzFRVE5GMiIsICJMWVZFMSIsICJUUkVNMSIsICJGT0xSMiIsICJDMVFCIiwJIkNDTDIiLCAiVE5GUlNGMTBDIiwgIkNYQ0w5IiwgIklMMVIyIiwgIklMMzZBIiwgIkNEMjgiLCAiT0FTMSIsICJJTDFSTiIsICJDRDM2IiwgIkNYQ1IyIiwJIlNFUlBJTkcxIiwgIkNYQ1IxIiwgIlRORlJTRjEwQyIsICJDMVFBIiwgIkhDU1QiLCAiSUwzNkEiLCAiSUw0UiIsICJMWTk2IiwgIklMMVIyIiwgIkNYQ1IyIiwgIkNYQ0wyIiwgIlMxMDBBNyIsICJJRklUTTMiLCAiU0VMRU5PTSIsICJTRUxFTk9QIiwgIkMzQVIxIiwgIkNDTDIiLCAiQ0NMOCIpCmdlbmVzJGVudHJ5IDwtIGMoIkFDRTIiLCAiVE1QUlNTMiIsICJCU0ciLCAiRFBQNCIsICJDVFNMIiwgIkNUU0IiLCAiRlVSSU4iKQpnZW5lcyRuZXcgPC0gYygiRkNHUlQiLCAiR1BYMSIsICJHUFgzIiwgIkdQWDQiLCAiRElPMyIsICJUWE5SRDEiLCAiVFhOUkQyIiwgIlRYTlJEMyIpCgphbGwuZ2VuZXMgPC0gYyhnZW5lcyRmb2N1c2VkLCBnZW5lcyRhbmFseXNpczEsIGdlbmVzJGFuYWx5c2lzMiwgZ2VuZXMkYWRkaXRpb25hbCwgZ2VuZXMkZW50cnksIGdlbmVzJG5ldykgJT4lIAogIHVuaXF1ZSgpICU+JSAKICBzb3J0KCkKYGBgCgojIFBsb3RzCiMjIERvdHBsb3QgZm9yIGFsbCBnZW5lcwoKYGBge3J9CiMgZG90cGxvdCBmdW5jdGlvbgpEb3RQbG90MiA8LSBmdW5jdGlvbihvYmplY3QgPSBzZXVyLCBhc3NheSA9ICJTQ1QiLCBmZWF0dXJlcywgdGl0bGUgPSAiIiwgLi4uKSB7CiAgcCA8LSBEb3RQbG90KG9iamVjdCwgCiAgICAgICAgICAgICAgIGFzc2F5ID0gYXNzYXksCiAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZmVhdHVyZXMsIAogICAgICAgICAgICAgICBkb3Quc2NhbGUgPSA0LCAKICAgICAgICAgICAgICAgZG90Lm1pbiA9IDAuMDEsCiAgICAgICAgICAgICAgIC4uLikgKwogICAgY29vcmRfZmxpcCgpICsKICAgIGxhYnMoY2FwdGlvbiA9IHBhc3RlMCgic2N0cmFuc2Zvcm0gbm9ybWFsaXplZCBleHByZXNzaW9uIiksIHRpdGxlID0gdGl0bGUpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjEpLAogICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjc1LCAibGluZSIpKQogIAogIHJldHVybihwKQp9CmBgYAoKYGBge3IgZmlnLmFzcD0xLjMsIGZpZy53aWR0aD02LjV9CkRvdFBsb3QyKGZlYXR1cmVzID0gYWxsLmdlbmVzKQoKY293cGxvdDo6Z2dzYXZlMihsYXN0X3Bsb3QoKSwgCiAgICAgICAgICAgICAgICAgZmlsZW5hbWUgPSAiLi4vcmVzdWx0cy8wM19jYW5kaWRhdGUtZ2VuZXMvcGxvdHMvZG90cGxvdF9hbGwtZ2VuZXMucGRmIiwgCiAgICAgICAgICAgICAgICAgd2lkdGggPSA2LjUsIGhlaWdodCA9IDguNSwgdW5pdHMgPSAiaW4iKQpgYGAKCiMjIEluZGl2aWR1YWwgZ2VuZXMKYGBge3J9CiMgdmlvbGluIGZ1bmN0aW9uClZsblBsb3QyIDwtIGZ1bmN0aW9uKG9iamVjdCA9IHNldXIsIGFzc2F5ID0gIlNDVCIsIGZlYXR1cmUsIC4uLikgewogIHAgPC0gVmxuUGxvdChvYmplY3QgPSBvYmplY3QsIAogICAgICAgICAgICAgICBmZWF0dXJlcyA9IGZlYXR1cmUsIAogICAgICAgICAgICAgICBhc3NheSA9IGFzc2F5LCAKICAgICAgICAgICAgICAgc2FtZS55LmxpbXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgc3BsaXQuYnkgPSAiY292aWQiLCAKICAgICAgICAgICAgICAgc3BsaXQucGxvdCA9IFRSVUUsCiAgICAgICAgICAgICAgIHB0LnNpemUgPSAwLAogICAgICAgICAgICAgICAuLi4pICsgCiAgICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUoCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcsIGNvbG91ciA9ICJibGFjayIpLAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjIpLAogICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMjUpLAogICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjI1KSwKICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSA2LCBjb2xvciA9ICJibGFjayIpLAogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG9yID0gImJsYWNrIiksCiAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC41MCwgImxpbmVzIiksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMSwgMSksCiAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAwKSwKICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9ICJibGFjayIpCiAgICApCiAgCiAgcCRsYXllcnNbWzFdXSRhZXNfcGFyYW1zJHNpemUgPSAwLjI1ICMgdmlvbGluIHN0cm9rZQogIAogIHJldHVybihwKQp9CmBgYAoKYGBge3J9CiMgdW1hcCBmdW5jdGlvbgpGZWF0dXJlUGxvdDIgPC0gZnVuY3Rpb24ob2JqZWN0ID0gc2V1ciwgZmVhdHVyZSwgLi4uKSB7CiAgRGVmYXVsdEFzc2F5KG9iamVjdCkgPC0gIlNDVCIKICBGZWF0dXJlUGxvdChvYmplY3QsIAogICAgICAgICAgICAgIGZlYXR1cmUgPSBmZWF0dXJlLCAKICAgICAgICAgICAgICBzcGxpdC5ieSA9ICJjb3ZpZCIsCiAgICAgICAgICAgICAgcHQuc2l6ZSA9IDAuMSwgCiAgICAgICAgICAgICAgb3JkZXIgPSBUUlVFLCAKICAgICAgICAgICAgICBtaW4uY3V0b2ZmID0gInExMCIsIAogICAgICAgICAgICAgIGNvbWJpbmUgPSBUUlVFLAogICAgICAgICAgICAgIC4uLikgJgogICAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gZmVhdHVyZSkgJgogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjI1KSwKICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNTAsICJsaW5lIiksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgIGF4aXMudGl0bGUueS5yaWdodCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEpCn0KYGBgCgoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5hc3A9MX0KCmZvcihpIGluIGFsbC5nZW5lc1thbGwuZ2VuZXMgJWluJSByb3duYW1lcyhzZXVyKV0pIHsKICB2cGxvdCA8LSBWbG5QbG90MihmZWF0dXJlID0gaSkKICBmcGxvdCA8LSBGZWF0dXJlUGxvdDIoZmVhdHVyZSA9IGksIG1heC5jdXRvZmYgPSAicTk5IikKICAKICBjb3dwbG90OjpnZ3NhdmUyKHZwbG90LCAKICAgICAgICAgICAgICAgICAgIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9yZXN1bHRzLzAzX2NhbmRpZGF0ZS1nZW5lcy9wbG90cy8iLCBpLCAiX3Zpb2xpbnBsb3QucGRmIiksCiAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDMuNSwgaGVpZ2h0ID0gMiwgdW5pdHMgPSAiaW4iKQogIAogIGNvd3Bsb3Q6Omdnc2F2ZTIoZnBsb3QsIAogICAgICAgICAgICAgICAgICAgZmlsZW5hbWUgPSBwYXN0ZTAoIi4uL3Jlc3VsdHMvMDNfY2FuZGlkYXRlLWdlbmVzL3Bsb3RzLyIsIGksICJfb24tdW1hcC5wbmciKSwKICAgICAgICAgICAgICAgICAgIHdpZHRoID0gMy41LCBoZWlnaHQgPSAyLjUsIHVuaXRzID0gImluIikKICAKICB2ZiA8LSB2cGxvdCArIGZwbG90ICsgCiAgcGxvdF9sYXlvdXQobmNvbCA9IDEsIHdpZHRocyA9IGMoMSwgMC41KSkKICBwcmludCh2ZikKfQpgYGAKCkZvciBzb21lIGdlbmVzLCB0aGUgdW1hcCBwbG90cyBhbmQgdmlvbGluIHBsb3RzIHNlZW0gdG8gZGlzYWdyZWUgd2l0aCBlYWNoIG90aGVyLiBUaGF0IGlzLCB0aGUgZ2VuZSBpcyBleHByZXNzZWQgYXQgaGlnaGVyIGxldmVsIGluICJjb3ZpZCIgdGhhbiAiY29udHJvbCIgYWNjb3JkaW5nIHRvIHRoZSB2aW9saW4gcGxvdCwgYnV0IHRoZSBjb2xvdXJzIGFwcGVhciBzdHJvbmdlciBmb3IgImNvbnRyb2wiIG9uIHVtYXAgcGxvdHMuIEkgdGhpbmsgdGhpcyBpcyBzaW1wbHkgYmVjYXVzZSBvZiB0aGUgZGlmZmVyaW5nIG51bWJlciBvZiBjZWxscyBmcm9tICJjb250cm9sIiBhbmQgImNvdmlkIi4gV2UgaGF2ZSBmZXdlciBjZWxscyBmcm9tICJjb3ZpZCIgc2FtcGxlcyAoYXMgaXMgZXZpZGVudCBhbHNvIG9uIHRoZSB1bWFwIHBsb3RzKSwgc28gdGhlIGxpZ2h0bmVzcyBvciBzcGFyc2VuZXNzIG9mIGJsdWUgb24gdW1hcCBwbG90cyBqdXN0IHJlZmxlY3QgdGhhdC4gVmlvbGluIHBsb3RzIG9uIHRoZSBvdGhlciBoYW5kIHNjYWxlIHRoZSB3aWR0aCBvZiB2aW9saW5zIHRvIHRoZSB0b3RhbCBudW1iZXIgb2YgY2VsbHMgaW4gZWFjaCBncm91cCwgc28gdGhpcyBkaWZmZXJlbmNlIGlzIG5vdCBzZWVuIGluIHZpb2xpbiBwbG90cy4KCiMgU3BsaXQgZG90cGxvdHMKYGBge3J9CiMjIGRhdGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KY2VsbHR5cGVzIDwtIHVuaXF1ZShzZXVyJGFubm90YXRpb25fbWVyZ2VkKSAlPiUgc29ydCgpCmRlLmdlbmVzIDwtIGxpc3QoKQpmb3IoaSBpbiBjZWxsdHlwZXMpewogIGRlLmdlbmVzW1tpXV0gPC0gcmVhZC5jc3YoCiAgICBwYXN0ZTAoIi4uL3Jlc3VsdHMvMDRfZGUtZ2VuZXMtYnktY2VsbHR5cGUvbG9nZmNfMC40MC9kZS9maWxlcy9kZS1nZW5lc18iLCBpLCAiLmNzdiIpCiAgKQogIGRlLmdlbmVzW1tpXV0gPC0gZHBseXI6OnJlbmFtZShkZS5nZW5lc1tbaV1dLCAiZ2VuZSIgPSAiWCIpCiAgZGUuZ2VuZXNbW2ldXSRjZWxsdHlwZSA8LSBpCn0KYGBgCgpgYGB7cn0KIyMgY3JlYXRlIGNlbGx0eXBlX2NvdmlkIGlkZW50IHRvIHVzZSBmb3Igc2V1cmF0IGRvdHBsb3QgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpzZXVyJGNlbGx0eXBlX2NvdmlkIDwtIHBhc3RlMChzZXVyJGFubm90YXRpb25fbWVyZ2VkLCAiXyIsIHNldXIkY292aWQpCmBgYAoKYGBge3J9CiMjIHRoZW1lIGZvciBERSBnZW5lcyBmYWNldGVkIGRvdHBsb3QgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KdGhlbWVfZG90cGxvdCA8LSB0aGVtZSgKICBwbG90Lm1hcmdpbiA9IG1hcmdpbig1LjUsIDUuNSwgMSwgNS41KSwKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiQmxhY2siKSwKICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIHNpemUgPSAwLjI1LCBjb2xvciA9ICJncmV5IiksCiAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSwgc2l6ZSA9IDUsIGNvbG9yID0gIkJsYWNrIiksCiAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUsIGNvbG9yID0gIkJsYWNrIiksCiAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjI1LCBjb2xvciA9ICJncmV5IiksCiAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gNS4yNSwgY29sb3IgPSAiQmxhY2siKSwKICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNS4yNSksCiAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICBsZWdlbmQuYm94ID0gImhvcml6b250YWwiLAogIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLAogIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA1KSwKICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgbGVnZW5kLmtleSA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5zcGFjaW5nLnggPSB1bml0KDAsICJsaW5lcyIpCikKYGBgCgpgYGB7cn0KIyMgZG90cGxvdCBmdW5jdGlvbiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwbG90X3NwbGl0ZG90IDwtIGZ1bmN0aW9uKG9iamVjdCwgZmVhdHVyZXMsIGV4Y2x1ZGUuY2VsbHR5cGVzID0gYygpKSB7CiAgCiAgIyBpZGVudHMgY29tYmluZWQgZm9yIGNlbGx0eXBlIGFuZCBjb3ZpZAogIElkZW50cyhvYmplY3QpIDwtIG9iamVjdCRjZWxsdHlwZV9jb3ZpZAogIAogICMgcnVuIHNldXJhdCdzIGRvdHBsb3QKICBwIDwtIFNldXJhdDo6RG90UGxvdCgKICAgIG9iamVjdCA9IG9iamVjdCwgCiAgICBhc3NheSA9ICJTQ1QiLCAKICAgIGZlYXR1cmVzID0gZmVhdHVyZXMKICAgICkKICAKICAjIGV4dHJhY3QgcGxvdHRpbmcgZGF0YQogIHAuZGF0IDwtIHAkZGF0YQogIHAuZGF0JGNlbGx0eXBlIDwtIGdzdWIocC5kYXQkaWQsIHBhdHRlcm4gPSAiKC4rKV8oW2Etel17NX0pIiwgcmVwbGFjZW1lbnQgPSAiXFwxIikKICBwLmRhdCRjb3ZpZCA8LSBnc3ViKHAuZGF0JGlkLCBwYXR0ZXJuID0gIiguKylfKFthLXpdezV9KSIsIHJlcGxhY2VtZW50ID0gIlxcMiIpCiAgCiAgIyBzdWJzZXQgZm9yIGNlbGx0eXBlcyBvZiBpbnRlcmVzdAogIHAuc3ViIDwtIHAuZGF0WyEocC5kYXQkY2VsbHR5cGUgJWluJSBleGNsdWRlLmNlbGx0eXBlcyksIF0KICAKICAjIHJlZG8gc2NhbGluZyBmb3Igc2VsZWN0ZWQgY2VsbHR5cGVfY292aWQgaWRlbnRzCiAgcC53aWRlIDwtIHBpdm90X3dpZGVyKHAuc3ViLAogICAgICAgICAgICAgICAgICAgICAgICBpZF9jb2xzID0gZmVhdHVyZXMucGxvdCwgCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBpZCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gYXZnLmV4cCkgJT4lIAogICAgYXMuZGF0YS5mcmFtZSgpCiAgCiAgcm93bmFtZXMocC53aWRlKSA8LSBwLndpZGUkZmVhdHVyZXMucGxvdAogIHAud2lkZSRmZWF0dXJlcy5wbG90IDwtIE5VTEwKICBwLnNjYWxlZCA8LSB0KHAud2lkZSkgJT4lIAogICAgc2NhbGUoY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKSAlPiUgCiAgICB0KCkgJT4lIAogICAgYXMuZGF0YS5mcmFtZSgpCiAgcC5zY2FsZWQkZmVhdHVyZXMucGxvdCA8LSByb3duYW1lcyhwLnNjYWxlZCkKICAKICAjIG1lbHQgcmVzY2FsZWQgYXZnLmV4cAogIHAuc2NhbGVkLmxvbmcgPC0gcGl2b3RfbG9uZ2VyKAogICAgZGF0YSA9IHAuc2NhbGVkLCAKICAgIGNvbHMgPSBuYW1lcyhwLnNjYWxlZClbbmFtZXMocC5zY2FsZWQpICE9ICJmZWF0dXJlcy5wbG90Il0sIAogICAgbmFtZXNfdG8gPSAiaWQiLCAKICAgIHZhbHVlc190byA9ICJzY2FsZWQubmV3IikKICAKICAjIGNhcCBtaW4gYW5kIG1heCBzY2FsZWQgdmFsdWU7IHNhbWUgYXMgY29sLm1pbiBhbmQgY29sLm1heCBpbiBTZXVyYXQ6OkRvdFBsb3QKICBwLnNjYWxlZC5sb25nJHNjYWxlZC5uZXdbcC5zY2FsZWQubG9uZyRzY2FsZWQubmV3ID4gIDIuNV0gPC0gIDIuNQogIHAuc2NhbGVkLmxvbmckc2NhbGVkLm5ld1twLnNjYWxlZC5sb25nJHNjYWxlZC5uZXcgPCAtMi41XSA8LSAtMi41CiAgCiAgIyBqb2luIHdpdGggcC5kYXQgdG8gZ2V0IHBjdC5leHAgYW5kIHNjYWxlZC5uZXcgaW4gdGhlIHNhbWUgZGYKICBwbG90LmRhdCA8LSBkcGx5cjo6aW5uZXJfam9pbih4ID0gcC5kYXQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBwLnNjYWxlZC5sb25nLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoImZlYXR1cmVzLnBsb3QiLCAiaWQiKSkKICAKICAjIGNsdXN0ZXJpbmcgZm9yIG9yZGVyaW5nCiAgY2RhdCA8LSBwaXZvdF93aWRlcihkYXRhID0gIHBsb3QuZGF0LCBpZF9jb2xzID0gImZlYXR1cmVzLnBsb3QiLCAKICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBpZCwKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gc2NhbGVkLm5ldykgJT4lIAogICAgYXMuZGF0YS5mcmFtZSgpCgogIHJvd25hbWVzKGNkYXQpIDwtIGNkYXQkZmVhdHVyZXMucGxvdAogIGNkYXQkZmVhdHVyZXMucGxvdCA8LSBOVUxMCiAgY29yLm1hdHJpeCA8LSBjb3IodChjZGF0KSkKICAKICAjIHJlb3JkZXIgY29ycmVsYXRpb24gbWF0cml4IGJhc2VkIG9uIGNsdXN0ZXJpbmcKICBkZCA8LSBhcy5kaXN0KCgxIC0gY29yLm1hdHJpeCkpCiAgaGMgPC0gaGNsdXN0KGRkLCBtZXRob2QgPSAnY29tcGxldGUnKQogIGNkYXQgIDwtIGNkYXRbaGMkb3JkZXIsIF0KCiAgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMgYmFzZWQgb24gY2x1c3RlcmluZwogIHBsb3QuZGF0JGZlYXR1cmVzLnBsb3QgPC0gZmFjdG9yKHBsb3QuZGF0JGZlYXR1cmVzLnBsb3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHJvd25hbWVzKGNkYXQpKQogIAogICMgcHJlcGFyZSBhbm5vdGF0aW9uIGRhdGEgKGhwbGluZSBmb3IgREUgZ2VuZXMpCiAgZGUuYW5uIDwtIGRlLmdlbmVzCiAgZGUuYW5uIDwtIGRvLmNhbGwocmJpbmQsIGRlLmFubikKICBkZS5hbm4gPC0gc3Vic2V0KGRlLmFubiwgCiAgICAgICAgICAgICAgICAgICBnZW5lICVpbiUgcGxvdC5kYXQkZmVhdHVyZXMucGxvdCAmCiAgICAgICAgICAgICAgICAgICAgIGNlbGx0eXBlICVpbiUgcGxvdC5kYXQkY2VsbHR5cGUKICApCiAgZGUuYW5uJGRpZmYuZXhwIDwtIGRlLmFubiRwX3ZhbF9hZGogPCAwLjA1CiAgZGUuYW5uJGRpZmYuZXhwIDwtIHRvbG93ZXIoYXMuY2hhcmFjdGVyKGRlLmFubiRkaWZmLmV4cCkpCiAgCiAgIyBwbG90CiAgcSA8LSBnZ3Bsb3QoZGF0YSA9IHBsb3QuZGF0LCAKICAgICAgICAgICAgICBhZXMoeCA9IGNvdmlkLCB5ID0gZmVhdHVyZXMucGxvdCkpICsKICAgIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBzY2FsZWQubmV3LCBzaXplID0gcGN0LmV4cCksIAogICAgICAgICAgICAgICBzaGFwZSA9IDIxLCBzdHJva2UgPSAwLCAKICAgICAgICAgICAgICAgY29sb3IgPSAiV2hpdGUiKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJXaGl0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gIiNkOTQ4MDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJhdmcuIGV4cC4gKHNjYWxlZCkiLAogICAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2NvbG9yYmFyKAogICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLmhqdXN0ID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrcy5jb2xvdXIgPSAiYmxhY2siCiAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICkgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShicmVha3MgPSBjKCJjbnRybCIsICJjb3ZpZCIpLCAKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiY3RybCIsICJDT1ZJRCIpKSArCiAgICBzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSAyLjUsCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIlIGNlbGxzIHdpdGggZXhwLiIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQoCiAgICAgICAgICAgICAgICAgICAgICBvdmVycmlkZS5hZXMgPSBsaXN0KAogICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJXaGl0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gIkdyZXkzMCIKICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICB0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNQogICAgICAgICAgICAgICAgICAgICkKICAgICkgKwogICAgZmFjZXRfZ3JpZCguIH4gY2VsbHR5cGUpICsKICAgIHVuZ2V2aXo6Omdlb21faHBsaW5lKGRhdGEgPSBkZS5hbm4sCiAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeSA9IGdlbmUsIHggPSAxLjUsIGNvbG9yID0gZGlmZi5leHApLAogICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMzAsIHdpZHRoID0gMSwgbGluZWVuZCA9ICJidXR0IikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9ICJ0cnVlIiwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSAiPCAwLjA1IiwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSAiQmxhY2siLAogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiREUgYWRqLnAiLAogICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUuaGp1c3QgPSAwLjUpKSArCiAgICB0aGVtZV9kb3RwbG90CiAgCiAgcmV0dXJuKHEpCiAgCn0KCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5hc3A9MC40fQojIHBsb3QgbmV3IGdlbmUgbGlzdApzcGxpdGRvdDEgPC0gcGxvdF9zcGxpdGRvdCgKICBvYmplY3QgPSBzZXVyLCAKICBmZWF0dXJlcyA9IGdlbmVzJG5ldwopCgpjb3dwbG90OjpnZ3NhdmUyKAogIHNwbGl0ZG90MSwKICBmaWxlbmFtZSA9ICIuLi9yZXN1bHRzLzAzX2NhbmRpZGF0ZS1nZW5lcy9wbG90cy9zcGxpdGRvdF9zZXQxLnBkZiIsCiAgd2lkdGggPSAzLjc1LCBoZWlnaHQgPSAyLCB1bml0cyA9ICJpbiIKKQoKc3BsaXRkb3QxCmBgYAoKIyBNZWFuIGV4cHJlc3Npb24gZm9yIGFsbCBnZW5lcwoKYGBge3J9CmF2ZyA8LSBBdmVyYWdlRXhwcmVzc2lvbihzZXVyLCBhc3NheXMgPSAiU0NUIikgJT4lIC4kU0NUCmF2ZyRnZW5lX25hbWUgPC0gcm93bmFtZXMoYXZnKQphdmcgPC0gcmVsb2NhdGUoYXZnLCBnZW5lX25hbWUpCgp3cml0ZS5jc3YoYXZnLCAiLi4vcmVzdWx0cy8wM19jYW5kaWRhdGUtZ2VuZXMvbWVhbi1leHByZXNzaW9uX2Fzc2F5LXNjdF9zbG90LWRhdGEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKCiMgU2Vzc2lvbiBJbmZvCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoK